#include "app_message.h"
#include "thirdparty/cJSON.h"
#include "thirdparty/log.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


// 将二进制转换为字符串，调用者需要释放str
static char* bin_to_str(unsigned char* binary, size_t len)
{
    char* hex_str = malloc(len * 2 + 1);
    if(!hex_str)
    {
        log_warn("Not enough memory");
        return NULL;
    }
    for (size_t i=0; i<len;i++)
    {
        sprintf(hex_str + i*2, "%02X", binary[i]);
    }
    hex_str[len*2] = '\0';
    return hex_str;
}

// 将字符串转换为2进制数据返回实际转换的长度
static int str_to_bin(char* hex_str, void *binary, int len)
{
    if(strlen(hex_str) % 2 != 0)
    {
        log_warn("Hex string is not valid");
        return -1;
    }
    if(len < (int)strlen(hex_str)/ 2)
    {
        log_warn("Buffer len is not enough");
        return -1;
    }

    len = strlen(hex_str) / 2;
    for (int i = 0 ; i < len; i++) {
        sscanf(hex_str + i*2, "%02X", (unsigned int*)(binary + i));  // binary + i 是 void* 指针算术
    }
    return len;
}

int app_message_initByBinary(Message* message, void* binary, int len)
{
    memset(message, 0, sizeof(Message));
    memcpy(&message->connection_type, binary, 1);
    memcpy(&message->id_len, binary+1, 1);  // 小端序：直接复制
    memcpy(&message->data_len, binary+2, 1); // 小端序：直接复制
    if (len != message->id_len + message->data_len + 3) {
        log_error("Message is not valid");
        return -1;
    }

    message->payload = malloc(message->id_len + message->data_len);
    if(!message->payload)
    {
        log_warn("Not enough for message");
        return -1;
    }

    memcpy(message->payload, binary+3, message->id_len + message->data_len);
    return 0;
}

int app_message_initByJson(Message* message, void *json_str, int len)
{
    // 使用出JSON解析字符串
    cJSON *json_object = cJSON_ParseWithLength(json_str, len);
    cJSON *connection_type = cJSON_GetObjectItem(json_object, "connection_type");
    message->connection_type = connection_type->valueint;

    cJSON *id = cJSON_GetObjectItem(json_object, "id");
    if(strlen(id->valuestring)%2 != 0)
    {
        log_warn("Message is not valid");
        return -1;
    }
    message->id_len = strlen(id->valuestring) /2;
    cJSON *data = cJSON_GetObjectItem(json_object, "data");
    if(strlen(data->valuestring)%2 != 0)
    {
        log_warn("Message is not valid");
        return -1;
    }
    message->data_len = strlen(data->valuestring)/2;

    message->payload = malloc(message->id_len + message->data_len);
    if(!message->payload)
    {
        log_warn("Not enough for message");
        return -1;
    }

    if (str_to_bin(id->valuestring, message->payload, message->id_len)< 0) {
        log_warn("Convertion failed");
        free(message->payload);
        return -1;
    }

    if (str_to_bin(data->valuestring, message->payload + message->id_len, message->data_len) < 0) {
        log_warn("Convertion failed");
        free(message->payload);
        return -1;
    }
    cJSON_Delete(json_object);
    return 0;
}
int app_message_saveBinary(Message *message, void *binary, int len)
{
    if(len < message->id_len + message->data_len+3)
    {
        log_warn("Buffer not enough for message");
        return -1;
    }
    memcpy(binary, &message->connection_type, 1);
    memcpy(binary+1, &message->id_len, 1);
    memcpy(binary+2, &message->data_len, 1);
    memcpy(binary+3, message->payload, message->id_len + message->data_len);
    return message->id_len + message->data_len + 3;
}

int app_message_saveJson(Message *message, void *json_str, int len)
{
    // 首先生成一个JSON——OBJECT
    cJSON *json_object = cJSON_CreateObject();
    cJSON_AddNumberToObject(json_object, "connection_type", message->connection_type);
    cJSON_AddStringToObject(json_object, "id", bin_to_str(message->payload, message->id_len));
    cJSON_AddStringToObject(json_object, "data", bin_to_str(message->payload+message->id_len, message->data_len));

    char *str = cJSON_PrintUnformatted(json_object);

    if(len < (int)strlen(str) + 1)
    {
        log_warn("Buffer not enough for message");
        return -1;
    }

    strcpy(json_str, str);
    cJSON_free(str);
    cJSON_Delete(json_object);
    return 0;
}

void app_message_free(Message *message)
{
    if(message->payload)
    {
        free(message->payload);
        message->payload = NULL;
    }
}